//////////////////////////////////////////////////////////////////////////////
//    Copyright 2004, SenseGraphics AB
//
//    This file is free software; you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation; either version 2 of the License, or
//    (at your option) any later version.
//
//    H3D API is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Public License for more details.
//
//    You should have received a copy of the GNU General Public License
//    along with H3D API; if not, write to the Free Software
//    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//    A commercial license is also available. Please contact us at 
//    www.sensegraphics.com for more information.
//
//
/// \file Torus.cpp
/// \brief CPP file for Torus, X3D scene-graph node
///
//
//
//////////////////////////////////////////////////////////////////////////////

#include "Torus.h"

#ifdef HAVE_GLUT
#include <GL/glut.h>
#endif

using namespace H3D;

// Add this node to the H3DNodeDatabase system.
H3DNodeDatabase Torus::database( "Torus", 
                                  &(newInstance<Torus>), 
                                  typeid( Torus ),
                                  &X3DGeometryNode::database );

// Define the x3d interface
namespace TorusInternals {
  FIELDDB_ELEMENT( Torus, innerRadius, INPUT_OUTPUT );
  FIELDDB_ELEMENT( Torus, outerRadius, INPUT_OUTPUT );
  FIELDDB_ELEMENT( Torus, nrSides, INPUT_OUTPUT );
  FIELDDB_ELEMENT( Torus, nrRings, INPUT_OUTPUT );
  FIELDDB_ELEMENT( Torus, solid, INPUT_OUTPUT );
}

Torus::Torus( 
         Inst< SFNode  >  _metadata,
         Inst< SFBound >  _bound,
	 Inst< DisplayList > _displayList,
	 Inst< MFBool      > _isTouched,
	 Inst< MFVec3f     > _force,
	 Inst< MFVec3f     > _contactPoint,
	 Inst< MFVec3f     > _contactNormal,
	 Inst< MFVec3f     > _contactTexCoord,
	 Inst< SFBoundTree > _boundTree,
         Inst< SFFloat >  _innerRadius,
         Inst< SFFloat >  _outerRadius,
         Inst< SFInt32 >  _nrSides,
         Inst< SFInt32 >  _nrRings,
         Inst< SFBool  >  _solid ) :
  X3DGeometryNode( _metadata, _bound, _displayList, _isTouched, _force, 
		   _contactPoint, _contactNormal, _contactTexCoord, _boundTree ),
  innerRadius    ( _innerRadius ),
  outerRadius    ( _outerRadius ),
  nrSides        ( _nrSides ),
  nrRings        ( _nrRings ),
  solid          ( _solid    ) {

  type_name = "Torus";
  database.initFields( this );

  // set default values
  innerRadius->setValue( 0.5 );
  outerRadius->setValue( 1 );
  nrSides->setValue( 40 );
  nrRings->setValue( 40 );
  solid->setValue( true );

  // set up bound routes
  innerRadius->route( bound );
  outerRadius->route( bound );
  
  // set up display list routes(each field that if changed 
  // requires a rerendering of the torus should be routed in here)
  innerRadius->route( displayList );
  outerRadius->route( displayList );
  nrSides->route( displayList );
  nrRings->route( displayList );
  solid->route( displayList );

#ifndef HAVE_GLUT
  Console(4) << "Torus node cannot be used. Compiled without HAVE_GLUT." << endl;
#endif 

}

void Torus::render() {
#ifdef HAVE_GLUT
  glutSolidTorus( innerRadius->getValue(), 
                  outerRadius->getValue(), 
                  nrSides->getValue(),
                  nrRings->getValue() );
#endif
}

void Torus::traverseSG( TraverseInfo &ti ) {
  if( solid->getValue() ) {
    useBackFaceCulling( true );
  } else {
    useBackFaceCulling( false );
  }
  X3DGeometryNode::traverseSG( ti );
}
